
#include "MCU.h"
#include "peripheral.h"

#include "contract.h"
#include "IO.h"

typedef struct Uart{
	uint32_t entity;
	void(*cb)(uint8_t);
}Uart_T;

typedef struct UartHw{
	IO_T tx;
	IO_T rx;
	rcu_periph_enum rcu;
	IRQn_Type irqn;
}UartHw_T;

static void uart_rx_dummy(uint8_t rx){
	(void)rx;
}

static Uart_T uarts[] = {
	[0] = {	.entity = USART0,uart_rx_dummy},
	[1] = {	.entity = USART1,uart_rx_dummy},
	[2] = {	.entity = USART2,uart_rx_dummy},
	[3] = {	.entity = UART3, uart_rx_dummy},
	[4] = {	.entity = UART4, uart_rx_dummy},
};

static const UartHw_T uartHws[] = {
	[0] = {
		.tx = IO_INIT_TABLE(GPIOA, GPIO_PIN_9),
		.rx = IO_INIT_TABLE(GPIOA, GPIO_PIN_10),
		.rcu = RCU_USART0,
		.irqn = USART0_IRQn,
	},
	
	[1] = {
		.tx = IO_INIT_TABLE(GPIOA, GPIO_PIN_2),
		.rx = IO_INIT_TABLE(GPIOA, GPIO_PIN_3),
		.rcu = RCU_USART1,
		.irqn = USART1_IRQn,
	},
	
	[2] = {
		.tx = IO_INIT_TABLE(GPIOB, GPIO_PIN_10),
		.rx = IO_INIT_TABLE(GPIOB, GPIO_PIN_11),
		.rcu = RCU_USART2,
		.irqn = USART2_IRQn,
	},
	
#if 1
	[3] = {
		.tx = IO_INIT_TABLE(GPIOC, GPIO_PIN_10),
		.rx = IO_INIT_TABLE(GPIOC, GPIO_PIN_11),
		.rcu = RCU_UART3,
		.irqn = UART3_IRQn,
	},
	
	[4] = {
		.tx = IO_INIT_TABLE(GPIOC, GPIO_PIN_12),
		.rx = IO_INIT_TABLE(GPIOD, GPIO_PIN_2),
		.rcu = RCU_UART4,
		.irqn = UART4_IRQn,
	},
#endif 

};


static void BSP_Uart_IrqHandler(Uart_T* uart){
    if(RESET != usart_interrupt_flag_get(uart->entity, USART_INT_FLAG_RBNE)){
        /* read one byte from the receive data register */
        uint8_t rx = (uint8_t)usart_data_receive(uart->entity);
		uart->cb(rx);
    }
}

void USART0_IRQHandler(void)
{
	BSP_Uart_IrqHandler(&uarts[0]);
}

void USART1_IRQHandler(void)
{
	BSP_Uart_IrqHandler(&uarts[1]);
}

void USART2_IRQHandler(void)
{
	BSP_Uart_IrqHandler(&uarts[2]);
}

void UART3_IRQHandler(void)
{
	BSP_Uart_IrqHandler(&uarts[3]);
}

void UART4_IRQHandler(void)
{
	BSP_Uart_IrqHandler(&uarts[4]);
}

static int BSP_Uart_CheckIO(const IO_T* io){
	return io && io->port != 0;
}

static void BSP_Uart_HwInit(const UartHw_T* hw){

    /* USART interrupt configuration */
    nvic_irq_enable(hw->irqn, 3, 0);

    /* enable USART clock */
    rcu_periph_clock_enable(hw->rcu);

	if(BSP_Uart_CheckIO(&hw->tx)){
		IO_Init(&hw->tx, GPIO_MODE_AF_PP);
	}
	if(BSP_Uart_CheckIO(&hw->rx)){
		IO_Init(&hw->rx, GPIO_MODE_IPU);
	}
}

static void BSP_Uart_Config(const Uart_T* uart, uint32_t baud){
	uint32_t com = uart->entity;
    /* USART configure */
    usart_deinit(com);
    usart_baudrate_set(com, baud);
    usart_word_length_set(com, USART_WL_8BIT);
    usart_stop_bit_set(com, USART_STB_1BIT);
    usart_parity_config(com, USART_PM_NONE);
    usart_hardware_flow_rts_config(com, USART_RTS_DISABLE);
    usart_hardware_flow_cts_config(com, USART_CTS_DISABLE);
    usart_receive_config(com, USART_RECEIVE_ENABLE);
    usart_transmit_config(com, USART_TRANSMIT_ENABLE);
    usart_enable(com);	

	/* enable  receive interrupt */
    usart_interrupt_enable(com, USART_INT_RBNE);
	usart_interrupt_flag_clear(com, USART_INT_RBNE);
}

void BSP_Uart_Init(uint8_t id){
	REQUIRE(id < 5);
	BSP_Uart_HwInit(&uartHws[id]);
	BSP_Uart_Config(&uarts[id], 115200);
}


void BSP_Uart_Deinit(uint8_t id){
	REQUIRE(id < 5);
	usart_deinit(uarts[id].entity);
}

void BSP_Uart_SetBaud(uint8_t id, uint32_t baud){
	REQUIRE(id < 5);
	usart_baudrate_set(uarts[id].entity, baud);
}


void BSP_Uart_SetRxCallback(uint8_t id, void(*cb)(uint8_t rx)){
	REQUIRE(id < 5);
	REQUIRE(cb);
	uarts[id].cb = cb;
}

void BSP_Uart_Send(uint8_t id, uint8_t tx){
	uint32_t i = 0;
	uint32_t com = uarts[id].entity;
	REQUIRE(id < 5);
	
    while(RESET == usart_flag_get(com, USART_FLAG_TBE)){
		if(++i > 100000){
			break;
		}
	}
    usart_data_transmit(com, tx);
    while(RESET == usart_flag_get(com, USART_FLAG_TBE)){
		if(++i > 100000){
			break;
		}
	}
}

void BSP_Uart_SendBuf(uint8_t id, const uint8_t buf[], uint32_t len){
	uint32_t i;

	for(i = 0; i < len; i++){
		BSP_Uart_Send(id, buf[i]);
	}
}


